
#include <bits/stdc++.h>
using namespace std;

// 定义常量：最大数组大小和取模值
const int MAXN = 250000 + 5;
const int MOD = 998244353;
int BSize;

// 快速幂函数：计算a^n mod MOD，默认计算a的逆元(n=MOD-2)
inline int qpow(int a, int n = MOD - 2) {
  int res = 1;
  while (n) {
    if (n & 1) // 如果n为奇数，乘上当前a
      res = 1ll * res * a % MOD;
    a = 1ll * a * a % MOD; // a自乘平方
    n >>= 1;               // n右移一位(等价于除以2取整)
  }
  return res;
}
int block_id[MAXN]; // 每个元素所属的块编号

// 查询结构体：存储查询的左右边界、参数和编号
struct Query {
  int l, r, x, id;
  // 自定义排序规则：按块编号排序，奇数块升序，偶数块降序(优化缓存)
  bool operator<(const Query &other) const {
    if (block_id[l] != block_id[other.l])
      return block_id[l] < block_id[other.l];
    if (block_id[l] & 1)
      return r < other.r;
    else
      return r > other.r;
  }
};

// 全局数据结构
Query q[MAXN];                   // 存储所有查询
int fac[MAXN], inv_fac[MAXN];    // 阶乘和逆阶乘数组
int inv_num[MAXN];               // 逆元数组
int element_count[MAXN];         // 元素出现次数计数
int block_sum[MAXN];             // 块内元素总数
int block_inv_fac_product[MAXN]; // 块内逆阶乘乘积
int ans[MAXN];                   // 存储查询结果
int a[MAXN];                     // 存储输入数组

// 预处理函数：计算阶乘、逆阶乘和逆元
void prework() {
  fac[0] = 1;
  for (int i = 1; i < MAXN; ++i)
    fac[i] = 1ll * fac[i - 1] * i % MOD; // 计算阶乘

  inv_fac[MAXN - 1] = qpow(fac[MAXN - 1]); // 计算最大下标的逆阶乘
  for (int i = MAXN - 2; i >= 0; --i)
    inv_fac[i] = 1ll * inv_fac[i + 1] * (i + 1) % MOD; // 逆阶乘递推

  // 计算1/i MOD MOD (用于元素计数的逆元)
  for (int i = 1; i < MAXN; ++i)
    inv_num[i] = 1ll * fac[i - 1] * inv_fac[i] % MOD;
}

// 添加或删除元素
// x:元素值, d:1表示添加, -1表示删除
void add(int x, int delta) {

  int id = block_id[x];
  block_sum[id] += delta; // 更新块内元素总数

  if (delta == 1) {     // 添加元素
    ++element_count[x]; // 增加元素计数
    // 更新块内逆阶乘乘积：乘以新计数的逆元
    block_inv_fac_product[id] =
        1ll * block_inv_fac_product[id] * inv_num[element_count[x]] % MOD;
  } else { // 删除元素
    // 更新块内逆阶乘乘积：乘以当前计数(恢复之前的逆元)
    block_inv_fac_product[id] =
        1ll * block_inv_fac_product[id] * element_count[x] % MOD;
    --element_count[x]; // 减少元素计数
  }
}

// id 是元素值的间接映射：通过值范围而非数组索引划分，与 a 数组的存储顺序无关
//  查询函数：计算前d个块的组合结果
int query(int d) {
  if (d <= 0)
    return 1; // 边界条件：d<=0返回1
  int s = 0, m = 1;

  // 处理完整块的部分
  for (int id = 1; id <= d / BSize; ++id) {
    s += block_sum[id]; // 累加块内元素总数

    // 累乘块内逆阶乘乘积
    m = 1ll * m * block_inv_fac_product[id] % MOD;
  }

  // 处理不完整块的部分
  for (int id = (d / BSize) * BSize + 1; id <= d; ++id) {
    s += element_count[id];                         // 累加元素出现次数
    m = 1ll * m * inv_fac[element_count[id]] % MOD; // 累乘逆阶乘
  }

  // 返回组合数结果：s! * m MOD MOD
  return 1ll * fac[s] * m % MOD;
}

int main() {
  ios::sync_with_stdio(false); // 关闭输入输出同步，加速IO
  cin.tie(nullptr);            // 解除cin与cout的绑定

  // 全局变量定义
  int n, m;      // n:元素数量, m:查询数量
  prework();     // 执行预处理
  cin >> n >> m; // 读取元素数量和查询数量

  for (int i = 1; i <= n; ++i)
    cin >> a[i]; // 读取数组元素

  BSize = sqrt(n); // 分块大小
  // 计算分块大小
  for (int i = 1; i <= n; ++i)
    block_id[i] = (i - 1) / BSize + 1; // 计算每个元素所属块编号
  // 初始化块内逆阶乘乘积为1
  for (int i = 1; i <= (n - 1) / BSize + 1; ++i)
    block_inv_fac_product[i] = 1;

  // 读取所有查询
  for (int i = 1; i <= m; ++i) {
    int l, r, x;
    cin >> l >> r >> x;
    q[i] = {l, r, x, i};
  }

  // 排序查询（按自定义排序规则）
  sort(q + 1, q + m + 1);
  int L = 1, R = 0; // 当前区间左右边界

  // 处理所有查询
  for (int i = 1; i <= m; ++i) {
    // 移动左右指针，调整当前区间
    while (R < q[i].r)
      add(a[++R], 1);
    while (L > q[i].l)
      add(a[--L], 1);
    while (R > q[i].r)
      add(a[R--], -1);
    while (L < q[i].l)
      add(a[L++], -1);

    // 计算查询结果
    ans[q[i].id] = query(q[i].x - 1);
  }

  // 输出所有查询结果
  for (int i = 1; i <= m; ++i)
    cout << ans[i] << '\n';

  return 0;
}